package com.lql.linkedtable;

/**
 * 双向链表的增删改查
 */
public class DoubleLinkedListDemo {
    public static void main(String[] args) {
        //定义节点
        DoubleHeroNode hero1 = new DoubleHeroNode(1, "宋江", "及时雨");
        DoubleHeroNode hero2 = new DoubleHeroNode(2, "林冲", "豹子头");
        DoubleHeroNode hero3 = new DoubleHeroNode(3, "武松", "啊哈哈");
        DoubleHeroNode hero4 = new DoubleHeroNode(4, "鲁智深", "啊嘿嘿");
        // 添加节点
        DoubleLinkedList doubleLinkedList = new DoubleLinkedList();
        doubleLinkedList.addNodeByNo(hero4);
        doubleLinkedList.addNodeByNo(hero1);
        doubleLinkedList.addNodeByNo(hero2);
        doubleLinkedList.addNodeByNo(hero3);
        // 显示链表
        doubleLinkedList.showDoubleNode();
        System.out.println("________________________");
        // 更新节点信息
        DoubleHeroNode hero5 = new DoubleHeroNode(3, "鲁智深", "啊嘿嘿");
        doubleLinkedList.updateNode(hero5);
        doubleLinkedList.showDoubleNode();
        System.out.println("________________________");
        //删除节点
        doubleLinkedList.deleteNode(4);
        doubleLinkedList.showDoubleNode();
    }
}

class DoubleLinkedList {
    private final DoubleHeroNode head = new DoubleHeroNode(0, "", "");

    /**
     * 打印双向链表
     */
    public void showDoubleNode() {
        DoubleHeroNode next = head.getNext();
        while (next != null) {
            System.out.println(next);
            next = next.getNext();
        }
    }

    /**
     * 在双向链表的尾部插入新节点
     *
     * @param heroNode 待插入的节点
     */
    public void addNode(DoubleHeroNode heroNode) {
        DoubleHeroNode temp = head;
        while (temp.getNext() != null) {
            temp = temp.getNext();
        }
        //TODO 不一样的地方没改
        //temp.next = heroNode
        temp.setNext(heroNode);
        // hero.pre = temp
        heroNode.setPre(temp);
    }

    /**
     * 根据节点编号no，修改双向链表节点信息
     *
     * @param heroNode 待修改的节点
     */
    public void updateNode(DoubleHeroNode heroNode) {
        DoubleHeroNode temp = head.getNext();
        //标志待修改节点是否找到
        boolean flag = false;
        //链表为空
        if (temp == null) {
            throw new RuntimeException("链表为空，修改失败");
        }
        while (true) {
            if (temp == null) {
                //链表遍历到表尾未找到
                break;
            }
            if (temp.getNo() == heroNode.getNo()) {
                //插入位置已经找到
                flag = true;
                break;
            }
            temp = temp.getNext();
        }
        if (!flag) {
            //不存在该节点
            throw new RuntimeException("不存在该节点，修改失败");
        }
        temp.setName(heroNode.getName());
        temp.setNickName(heroNode.getNickName());
    }

    /**
     * 根据编号删除双向链表中的节点
     *
     * @param no 待删除节点的编号
     */
    public void deleteNode(int no) {
        if (head.getNext() == null) {
            //链表为空
            throw new RuntimeException("链表为空，删除失败");
        }
        DoubleHeroNode temp = head;
        //标志待删除节点是否找到
        boolean flag = false;
        while (true) {
            if (temp.getNo() == no) {
                //找到待删除结点
                flag = true;
                break;
            }
            if (temp.getNext() == null) {
                // 链表遍历到结尾，未找到待删除结点
                break;
            }
            temp = temp.getNext();
        }
        if (!flag) {
            throw new RuntimeException("不存在该节点，删除失败");
        }
        // 删除的不是尾节点
        if (temp.getNext() != null) {
            // temp.pre.next = temp.next
            temp.getPre().setNext(temp.getNext());
            // temp.next.pre = temp.pre
            temp.getNext().setPre(temp.getPre());
        }
        //删除的是尾节点
        //temp.pre.next = null
        temp.getPre().setNext(null);
    }

    /**
     * 按照编号顺序在双向链表中添加英雄
     *
     * @param heroNode 待插入的节点
     */
    public void addNodeByNo(DoubleHeroNode heroNode) {
        DoubleHeroNode temp = head;
        //标志节点是否已经存在
        boolean flag = false;
        while (true) {
            if (temp.getNext() == null) {
                // 已经遍历到尾节点，新插入节点应在在链表尾部
                break;
            }
            if (temp.getNext().getNo() > heroNode.getNo()) {
                //找出插入位置节点的前一个节点
                break;
            } else if (temp.getNext().getNo() == heroNode.getNo()) {
                //节点已经存在这个编号的节点，无法插入
                flag = true;
                break;
            }
            //继续向下遍历
            temp = temp.getNext();
        }
        if (flag) {
            throw new RuntimeException("节点已经存在，插入失败");
        }
        if(temp.getNext()!=null){
            //不在链表尾部
            // heroNode.next = temp.next
            heroNode.setNext(temp.getNext());
            // temp.next = heroNode
            temp.setNext(heroNode);
            // heroNode.next.pre = heroNode
            heroNode.getNext().setPre(heroNode);
            // heroNode.pre = temp
            heroNode.setPre(temp);
        }
        // 在链表尾部
        //temp.next = heroNode
        temp.setNext(heroNode);
        // hero.pre = temp
        heroNode.setPre(temp);
    }
}

class DoubleHeroNode {
    private int no;
    private String name;
    private String nickName;
    private DoubleHeroNode next;
    private DoubleHeroNode pre;

    public DoubleHeroNode(int no, String name, String nickName) {
        this.no = no;
        this.name = name;
        this.nickName = nickName;
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getNickName() {
        return nickName;
    }

    public void setNickName(String nickName) {
        this.nickName = nickName;
    }

    public DoubleHeroNode getNext() {
        return next;
    }

    public void setNext(DoubleHeroNode next) {
        this.next = next;
    }

    public DoubleHeroNode getPre() {
        return pre;
    }

    public void setPre(DoubleHeroNode pre) {
        this.pre = pre;
    }

    @Override
    public String toString() {
        return "HeroNode{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", nickName='" + nickName + '\'' +
                '}';
    }
}

